import static org.junit.Assert.*;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.junit.*;


/**
 * Een testklasse voor de klasse Square.
 * Deze bevat alle testmethoden om setters en speciale mutators
 * te controlleren van de klasse 'vakje'.
 * 
 * 
 * @author Nathan Bekaert & Philippe de Potter de ten Broeck
 * @version 1.0
 */
public class TestSquare {
	
	Square square1;
	Square square2;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}
	@Before
	public void setUp() throws Exception {
		square1 = new Square();
		square2 = new Square(Temperature.CELSIUS_0,new BigDecimal(50.00));
	}
	@After
	public void tearDown() throws Exception {
	}
	
	
	//TEMPERATUUR (Defensief)
	
	@Test
	public void testTemperatureLimits(){
		assertEquals(square1.getLowerLimitTemperature().getNumeral(),new BigDecimal(-200));
		assertEquals(square1.getLowerLimitTemperature().getTemperatureUnit(),TemperatureUnit.CELSIUS);
		assertEquals(square1.getUpperLimitTemperature().getNumeral(),new BigDecimal(5000));
		assertEquals(square1.getUpperLimitTemperature().getTemperatureUnit(),TemperatureUnit.CELSIUS);
	}
	@Test
	public void testChangedTemperatureLimits() throws Exception{
		square1.setLimitsTemperature(new Temperature(BigDecimal.ZERO,TemperatureUnit.CELSIUS), 
				new Temperature(new BigDecimal(200),TemperatureUnit.CELSIUS));
		assertEquals(square1.getLowerLimitTemperature().getNumeral(),new BigDecimal(0));
		assertEquals(square1.getLowerLimitTemperature().getTemperatureUnit(),TemperatureUnit.CELSIUS);
		assertEquals(square1.getUpperLimitTemperature().getNumeral(),new BigDecimal(200));
		assertEquals(square1.getUpperLimitTemperature().getTemperatureUnit(),TemperatureUnit.CELSIUS);
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNotMatching() throws Exception{
		square1.setLimitsTemperature(new Temperature(new BigDecimal(500),TemperatureUnit.CELSIUS), 
				new Temperature(new BigDecimal(100),TemperatureUnit.CELSIUS));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNullUnderLimit() throws Exception{
		square1.setLimitsTemperature(null, 
				new Temperature(new BigDecimal(100),TemperatureUnit.CELSIUS));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNullUpperLimit() throws Exception{
		square1.setLimitsTemperature(new Temperature(new BigDecimal(500),TemperatureUnit.CELSIUS)
				,null);
	}
	@Test
	public void testTemperature(){
		assertEquals(square1.getTemperature().getNumeral(),BigDecimal.ZERO);
		assertEquals(square1.getTemperature().getTemperatureUnit(),TemperatureUnit.CELSIUS);
	}
	@Test 
	public void testChangedTemperatureConvertToLimit(){
		square1.convertTo(TemperatureUnit.KELVIN);
		square1.setTemperature(new Temperature(new BigDecimal(5273), TemperatureUnit.KELVIN));
		assertEquals(square1.getTemperature().getNumeral(),new BigDecimal(5273));
		assertEquals(square1.getTemperature().getTemperatureUnit(),TemperatureUnit.KELVIN);
	}
	@Test
	public void testChangedTemperature(){
		square1.convertTo(TemperatureUnit.FAHRENHEIT);
		square1.setTemperature(new Temperature(BigDecimal.ONE, TemperatureUnit.FAHRENHEIT));
		assertEquals(square1.getTemperature().getNumeral(),BigDecimal.ONE);
		assertEquals(square1.getTemperature().getTemperatureUnit(),TemperatureUnit.FAHRENHEIT);
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureTooLow(){
		square1.setTemperature(new Temperature(BigDecimal.ONE, TemperatureUnit.KELVIN));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureTooHigh(){
		square1.setTemperature(new Temperature(new BigDecimal(9400), TemperatureUnit.FAHRENHEIT));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureFalseConversion(){
		square1.setTemperature(new Temperature(new BigDecimal(30), TemperatureUnit.KELVIN));
	}
	
	//SCHADE door temp (defensief)
	
	@Test
	public void testColdDamage()throws Exception{
		square1.setTemperature(new Temperature(new BigDecimal(20), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(-5), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(-14), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(-15), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(-16), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(-91), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 8);
	}
	@Test (expected=ArithmeticException.class)
	public void testColdDamageOutOfLowerBound() throws Exception{
		square1.setLimitsTemperature(new Temperature(new BigDecimal(Long.MIN_VALUE), TemperatureUnit.CELSIUS),
				square1.getUpperLimitTemperature());
		square1.setTemperature(square1.getLowerLimitTemperature());
		square1.coldDamage();
	}
	@Test
	public void testHeatDamage()throws Exception{
		square1.setTemperature(new Temperature(new BigDecimal(20), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(35), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(49), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(50), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(51), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(118), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 5);
	}
	@Test (expected=ArithmeticException.class)
	public void testHeatDamageOutOfUpperBound() throws Exception{
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(),
				new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.setTemperature(square1.getUpperLimitTemperature());
		square1.heatDamage();
	}
	@Test
	public void testHeatDamageChanged()throws Exception{
		square1.setHeatDamageValueAt(new BigDecimal(20), 2);
		square1.setHeatDamageValueAt(new BigDecimal(50), 3);
		square1.setTemperature(new Temperature(new BigDecimal(30), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(50), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(69), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.setTemperature(new Temperature(new BigDecimal(70), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(71), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.setTemperature(new Temperature(new BigDecimal(181), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 6);
	}
	
	
	//Vochtigheid en roest(nominaal)
	
	@Test 
	public void testHumidity(){
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(1000),2))==0);
	}
	@Test 
	public void testHumidityChanged(){
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(8000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(8000),2))==0);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(1000),1))==0);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(0000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(000),2))==0);
	}
	@Test 
	public void testHumidityPres(){
		assertFalse(Square.isValidHumidity(new BigDecimal(BigInteger.valueOf(-5000),2)));
		assertFalse(Square.isValidHumidity(new BigDecimal(BigInteger.valueOf(20000),2)));
	}
	@Test
	public void testRustDamage(){
		assertEquals(square1.rustDamage(),0);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertEquals(square1.rustDamage(),10);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(3700),2));
		assertEquals(square1.rustDamage(),1);
	}

	
	//Gladheid (defensief):

	@Test 
	public void testSlippery(){
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyWater(){
		square1.setTemperature(Temperature.CELSIUS_1);
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(9900),2));
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertTrue(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertTrue(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyIce(){
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(2000),2));
		assertTrue(square1.isSlippery());
		assertTrue(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.setTemperature(Temperature.CELSIUS_1);
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(5000),2));
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.setTemperature(Temperature.CELSIUS_0);
		assertTrue(square1.isSlippery());
		assertTrue(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyMaterial(){
		square1.setSlipperyMaterialSlippery(true);
		assertTrue(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertTrue(square1.getSlipperyMaterial());
		
	}
	
	
	//Bewoonbaarheid (defensief):
	
	@Test 
	public void testInhabitability(){
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(000),2)) == 0);
	}
	@Test 
	public void testInhabitabilityChanged(){
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(7600),2));
		square1.setTemperature(new Temperature(new BigDecimal(BigInteger.valueOf(500),1), TemperatureUnit.CELSIUS));
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(-2),1)) == 0);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(2000),2));
		square1.setTemperature(new Temperature(new BigDecimal(BigInteger.valueOf(-150),1), TemperatureUnit.CELSIUS));
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(-10),1)) == 0);
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(), new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.setTemperature(new Temperature(new BigDecimal(Integer.MAX_VALUE), TemperatureUnit.CELSIUS));
		System.out.println(square1.getInhabitability());
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(-1713002111395.282226562500)) == 0);
	}
	@Test (expected=ArithmeticException.class)
	public void testInhabitabilityOutOfUpperBound() throws Exception{
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(1000),2));
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(), 
				new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.setTemperature(new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.getInhabitability();
	}
	@Test (expected=ArithmeticException.class)
	public void testInhabitabilityOutOfLowerBound() throws Exception{
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(1000),2));
		square1.setLimitsTemperature(new Temperature(new BigDecimal(Long.MIN_VALUE), TemperatureUnit.CELSIUS),
				square1.getUpperLimitTemperature());
		square1.setTemperature(new Temperature(new BigDecimal(Long.MIN_VALUE), TemperatureUnit.CELSIUS));
		square1.getInhabitability();
	}
	@Test (expected=IllegalStateException.class)
	public void testInhabitabilityHumidityOutOfBound() throws Exception{
		square1.setHumidity(new BigDecimal(BigInteger.valueOf(100000),2));
		square1.setTemperature(Temperature.CELSIUS_1);
		square1.getInhabitability();
	}
	
	//BORDERS:
	@Test
	public void testBordersInitialisation(){
		for(Square.BorderState state: square1.getBorders()){
			assertTrue(state == Square.BorderState.UNBLOCKED);
		}
	}
	@Test
	public void testBordersChanged(){
		square1.block(3);
		square1.block(4);
		assertTrue(square1.getBorderAt(3) == Square.BorderState.BLOCKED);
		assertTrue(square1.getBorderAt(4) == Square.BorderState.BLOCKED);
		square1.unblock(3);
		assertTrue(square1.getBorderAt(3) == Square.BorderState.UNBLOCKED);
	}
	@Test
	public void testBordersOutofBound(){
		square1.block(100);
		square1.block(0);
		square1.block(-5);
		for(Square.BorderState state: square1.getBorders()){
			assertTrue(state == Square.BorderState.UNBLOCKED);
		}
		for(int i = 1; i<=square1.getNbBorders(); i++)
			square1.block(i);
		square1.unblock(0);
		for(Square.BorderState state: square1.getBorders()){
			assertEquals(state, Square.BorderState.BLOCKED);
		}
	}
	@Test
	public void testBordersMerged(){
		square1.mergeWith(square2,1);
		square1.block(1);
		assertEquals(square1.getBorderAt(1), Square.BorderState.MERGED);
		square1.unblock(1);
		assertEquals(square1.getBorderAt(1), Square.BorderState.MERGED);
	}
	
	
	//MERGE:
	
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalNull(){
		square1.mergeWith(null, 3);
	}
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalOutOfLowerBound(){
		square1.mergeWith(square2, 0);
	}
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalOutOfUpperBound(){
		square1.mergeWith(square2, 7);
	}
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalThis(){
		square1.mergeWith(square1, 3);
	}
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalTempUnits(){
		Square square3 = new Square(new Temperature(new BigDecimal(33.4), 
				TemperatureUnit.KELVIN),new BigDecimal(33.1));
		square1.mergeWith(square3, 3);
	}
	@Test (expected=IllegalArgumentException.class)
	public void testMergeExceptionalMerged(){
		Square square3 = new Square();
		square2.mergeWith(square3, 5);
		square1.mergeWith(square2, 5);
	}
	@Test
	public void testMerge(){
		Square square3 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(1500),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(5901),2));
		square3.setSlipperyMaterialSlippery(true);
		square3.block(1);
		square3.block(2);
		square3.block(3);
		Square square4 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(400),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(8990),2));
		square4.block(2);
		square4.block(3);
		square4.block(4);
		square3.mergeWith(square4, 2);
		assertTrue(square3.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(85872607615340L),12), TemperatureUnit.CELSIUS))==0);
		assertTrue(square4.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(85872607615340L),12), TemperatureUnit.CELSIUS))==0);
		assertTrue(square3.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(7446),2))==0);
		assertTrue(square4.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(7446),2))==0);
		assertEquals(square3.getBorderAt(2), Square.BorderState.MERGED);
		assertEquals(square4.getBorderAt(2), Square.BorderState.MERGED);
		assertEquals(square3.getBorderAt(3), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(3), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(1), Square.BorderState.UNBLOCKED);
	}
	@Test
	public void testMerge0(){
		Square square3 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(100),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(000),2));
		square3.setSlipperyMaterialSlippery(true);
		square3.block(4);
		square3.block(5);
		Square square4 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(500),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(000),2));
		square4.block(2);
		square4.block(3);
		square4.block(4);
		square3.mergeWith(square4, 4);
		assertTrue(square3.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(300),1), TemperatureUnit.CELSIUS))==0);
		assertTrue(square4.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(300),1), TemperatureUnit.CELSIUS))==0);
		assertTrue(square3.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(000),2))==0);
		assertTrue(square4.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(000),2))==0);
		assertEquals(square3.getBorderAt(4), Square.BorderState.MERGED);
		assertEquals(square4.getBorderAt(4), Square.BorderState.MERGED);
		assertEquals(square3.getBorderAt(5), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(2), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(3), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(5), Square.BorderState.UNBLOCKED);
	}
	@Test
	public void testMerge100(){
		Square square3 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(200),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(10000),2));
		square3.setSlipperyMaterialSlippery(true);
		square3.block(1);
		square3.block(2);
		square3.block(3);
		Square square4 = new Square(new Temperature(new BigDecimal(BigInteger.valueOf(400),1), 
				TemperatureUnit.CELSIUS), new BigDecimal(BigInteger.valueOf(10000),2));
		square4.block(2);
		square4.block(3);
		square4.block(4);
		square3.mergeWith(square4, 2);
		assertTrue(square3.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(300),1), TemperatureUnit.CELSIUS))==0);
		assertTrue(square4.getTemperature().compareTo(new Temperature(
				new BigDecimal(BigInteger.valueOf(300),1), TemperatureUnit.CELSIUS))==0);
		assertTrue(square3.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(10000),2))==0);
		assertTrue(square4.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(10000),2))==0);
		assertEquals(square3.getBorderAt(2), Square.BorderState.MERGED);
		assertEquals(square4.getBorderAt(2), Square.BorderState.MERGED);
		assertEquals(square3.getBorderAt(3), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(3), Square.BorderState.BLOCKED);
		assertEquals(square4.getBorderAt(1), Square.BorderState.UNBLOCKED);
	}
}
